﻿using Microsoft.CodeAnalysis.CSharp.Syntax;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Xppend.CodeGenerator.Decorators
{

    internal class InjectConstructorDataContext
    {
        public string ClassName { get; set; }

        public IEnumerable<PropertyDeclarationSyntax> PropertyDeclarationList { get; set; }
    }

    internal class InjectConstructorDecorator : BaseDecorator<InjectConstructorDataContext>
    {
        public override bool HasDecorator(InjectConstructorDataContext dataContext)
        {
            var list = dataContext.PropertyDeclarationList;
            var propertyDeclares = from prop in list where HasInjectMeAttribute(prop) select prop;
            return propertyDeclares.Any();
        }

        private bool HasInjectMeAttribute(PropertyDeclarationSyntax propertyDeclare)
        {
            var attribueLists = propertyDeclare.AttributeLists;
            if (attribueLists == null) return false;
            if (attribueLists.Count == 0) return false;
            foreach (var attribueList in attribueLists)
            {
                foreach (var attribute in attribueList.Attributes)
                {
                    if (attribute.Name.ToString().Equals("InjectMe", StringComparison.OrdinalIgnoreCase)) return true;
                }
            }
            return false;
        }

        public override void Decorate(StringBuilder stringBuilder, InjectConstructorDataContext dataContext)
        {
            var list = dataContext.PropertyDeclarationList;
            var propertyDeclares = (from prop in list where HasInjectMeAttribute(prop) select prop).ToArray();
            var paras = (from prop in propertyDeclares
                         select Paralize(prop)).ToArray();

            CreateCtor(stringBuilder, dataContext.ClassName, paras);

        }

        public void CreateCtor(StringBuilder stringBuilder, string className, IEnumerable<Tuple<string, string>> paras)
        {
            var methodParas = paras.Select(p => $"{p.Item1} {FirstLow(p.Item2)}").ToArray();
            stringBuilder.AppendLine($"public {className} ({string.Join(",", methodParas)})");
            stringBuilder.AppendLine("{");
            foreach (var para in paras)
            {
                var propName = para.Item2;
                var paraName = FirstLow(propName);
                stringBuilder.AppendLine($"{propName} = {paraName};");
            }
            stringBuilder.AppendLine("}");

        }

        private string FirstLow(string str)
        {
            return $"{char.ToLower(str[0])}{str.Substring(1)}";
        }
        private Tuple<string, string> Paralize(PropertyDeclarationSyntax propertyDeclare)
        {
            var type = propertyDeclare.Type.ToString();
            var name = propertyDeclare.Identifier.ToString();
            return Tuple.Create(type, name);
        }
        public static InjectConstructorDecorator Instance { get; private set; } = new InjectConstructorDecorator();
    }
}